<?php
//我们常常将一个类的定义放在一个独立的文件中，
//并取名为这种形式：类名.class.php
class MySQLDB{
	private $link = null;	//用于存储建立的“连接资源”

	//用于存储mysqldb对象的6个连接基本信息
	private $host ;
	private $port ;
	private $name ;
	private $pass ;
	private $charset ;
	private $dbname ;

	//实现单例第2步：
	private static  $instance = null;

	//实现单例第3步：
	static  function GetDB( $conf ){
		//if( !isset( self::$instance ) ){	//这个判断常常用下一行来判断
		if( !(self::$instance instanceOf self) ){
			self::$instance = new self( $conf );
		}
		return self::$instance;
	}
	//实现单例第4步禁止克隆：
	private function __clone(){}
	//实现单例第1步：
	private function __construct( $conf ){
		//判断某项数据是否为空，如果为空就设置一个默认值去使用！
		$this->host = !empty($conf['host']) ? $conf['host'] : "localhost";
		$this->port = !empty($conf['port']) ? $conf['port'] : "3306";
		$this->name = !empty($conf['name']) ? $conf['name'] : "root";
		$this->pass = !empty($conf['pass']) ? $conf['pass'] : "abc123";
		$this->charset = !empty($conf['charset']) ? $conf['charset'] : "utf8";
		$this->dbname = !empty($conf['dbname']) ? $conf['dbname'] : "php38";
		
		//连接成功，则获得一个“连接资源”，否则，终止程序！
		$this->link  = mysql_connect("{$this->host}:{$this->port}", "{$this->name}", $this->pass) 
				or die("连接数据库服务器失败！");
		
		//第二个参数表示使用哪个连接资源，去设置编码
		//可以省略。如果省略，默认表示使用“最近”的连接资源
		//mysql_query("set names  {$this->charset}", $this->link);//这个工作可以单独去实现
		//下一行代码代替上一行代码：即凡是要“设置连接编码”，就找该方法：
		$this->setCharset($this->charset);
		
		//选定数据库：
		//mysql_query("use  {$this->dbname}", $this->link);		//这个工作也可以单独去实现
		//下一行代码代替上一行代码：即凡是要“选择数据库”，就找该方法：
		$this->setDb($this->dbname);
	}

	function setDB($db){
		mysql_query("use $db", $this->link);	//该连接资源使用的数据库修改为“另一个”数据；
	}
	function setCharset($charset){
		mysql_query("set names $charset", $this->link);	//也可以修改为另外的连接编码
	}

	//断开连接
	function closeDb(){
		mysql_close($this->link);
	}

	//这个只做原始的sql语句的执行并处理错误或返回结果，
	//不管是什么sql语句：增删改都无所谓！
	function query($sql){
		$result = mysql_query($sql,  $this->link);
		if( $result === false){
			echo "<p>发生错误了!";
			echo "<br />错误语句为：" . $sql;
			echo "<br />错误信息为：" . mysql_error();
			die();	//出错，就终止程序！
		}
		return $result;
	}

	//该方法用于实现数据库操作的增删改动作，
	//如果执行成功，就返回true，否则就终止程序
	function exec( $sql ){
		$result = $this->query( $sql );//结果一定是true
		$num = mysql_affected_rows($this->link);//获得的是受影响的行数
		return $num;
	}

	//该方法用于执行一条sql语句并返回“一行数据，而且
	//返回的该行数据是存储在一个数组中！
	function GetOneRow( $sql ){
		$result = $this->query($sql);	//得到结果集！
		//从结果集中，“取出”一行数据，并放入数组$rec
		//数组的下标就是该行数据的字段名！
		$rec = mysql_fetch_assoc( $result );
		return $rec;
	}

	//该方法用于执行一条sql语句并返回“多行行数据，而且
	//返回的该多行数据是存储在一个二维数组中！
	function  GetRows($sql){
		$result =  $this->query($sql);	//得到结果集！
		//从结果集中，一行一行“取出”数据，并放入数组$rec中
		//数组的下标就是该行数据的字段名！
		$rec = array();
		while ($re = mysql_fetch_assoc( $result ) ){
			$rec[] = $re;//$re是一个“一维数组”，代表一行数据
						//$rec 就是二维数组了
		}
		return $rec;
	}
	//该方法用于执行一条sql语句并返回“一个数据值"
	function  GetOneData($sql){
		$result =  $this->query($sql);	//得到结果集！
		//该结果集只有一行一列！
		$row = mysql_fetch_row( $result );//取出一行（虽然只有这一行）
		$data = $row[0];	//就是一个单值数据，也就是表中的一个单元格的内容
		return $data;
	}

	//如果对这个类的对象进行序列号，则只需要这6个属性序列化就可以了！
	function __sleep(){
		return array('host','port', 'name', 'pass', 'charset','dbname');
	}

	//如果对这个类的进行了序列化的对象数据，再进行反序列号，此时，对象数据可以恢复
	//但并不能完成“连接数据库”的工作，我们需要这里去完成该工作：
	//*
	function __wakeup(){
		$this->link  = mysql_connect("{$this->host}:{$this->port}", "{$this->name}", $this->pass) 
				or die("连接数据库服务器失败！");
		$this->setCharset($this->charset);
		
		$this->setDb($this->dbname);
	}
	//*/


}
